home *** CD-ROM | disk | FTP | other *** search
- /*
- C* -- System Interface Module with IO redirection support.
-
- Source: cppsys.c
- Started: October 7, 1985
- Version:
- April 2, 1987
- March 7, 1989
-
- PUBLIC DOMAIN SOFTWARE
-
- The CSTAR program was placed in the public domain on June 15, 1991,
- by its author and sole owner,
-
- Edward K. Ream
- 1617 Monroe Street
- Madison, WI 53711
- (608) 257-0802
-
- CSTAR may be used for any commercial or non-commercial purpose.
-
- See cstar.h or cstar.c for a DISCLAIMER OF WARRANTIES.
- */
- #include "cstar.h"
-
- /* Define STANDARD_C if the Compiler uses the standard C library. */
- #define STANDARD_C 1
-
- #ifdef MICRO_SOFT
- #include <fcntl.h>
- #include <sys\types.h>
- #include <sys\stat.h>
- #include <io.h>
- #endif
-
- #ifdef TURBOC
- #include <fcntl.h>
- #include <sys\stat.h>
- #include <io.h>
- #include <dos.h>
- #endif
-
- /*
- Externally visible routines:
- */
- void sysabort (void);
- void sysnext (void);
- void syspush (int c);
- void sysspush (char *s);
- void sysiclose (void);
- bool sysopen (char * name);
- bool syscreat (char * name);
- void sysoclose (void);
- void sysnlput (void);
- void syscput (char c);
- void syssput (char * s);
- void sysend (void);
- void sysinit (void);
- int syscsts (void);
-
- /*
- Internal routines:
- */
- static void sys_release (void);
- static struct FN *
- sys_new (int buf_size);
- static void sysnx1 (void);
- static void sys_close (register struct FN * fnp, int count);
- static void raw_close (int handle);
- static int raw_creat (char *name);
- static int raw_open (char *name);
- static int raw_read (int handle, char *buffer, int n);
- static void raw_write (int handle, char *buffer, int n);
-
-
- /*
- Define the format of a file node.
-
- The node contains all information pertaining to the file.
- The fil_name and f_line are used to update preprocessor globals.
- The f_line field is not used for output files.
- */
- static struct FN {
- struct FN * f_next; /* pointer to next node */
- char * fil_name; /* file name */
- int f_line; /* line number */
- char * f_buffer; /* file buffer */
- int f_bufsize; /* size of file buffer: bytes */
- int f_handle; /* File handle. */
- char * f_bufp; /* pointer into file buffer */
- int f_bufc; /* characters in buffer */
- int f_type; /* INPUT, OUTPUT, EOF_STAT, CLOSED */
- int f_lastc; /* last character of previous level */
- };
- #define FN_SIZE (sizeof(struct FN))
-
- static struct FN * in_list; /* List of input nodes. */
- static struct FN * outn_list; /* List of output nodes. */
-
- /*
- The following global variables are copies of the fields in FN.
- Global variables are used as an efficiency measure.
- */
- static char * s_ip; /* Copy of f_bufp for input file. */
- static int s_ic; /* Copy of f_bufc for input file. */
- static char * s_op; /* Copy of f_bufp for output file. */
- static int s_oc; /* Copy of f_bufc for output file. */
-
- #define CLOSED 1
- #define INPUT 2
- #define OUTPUT 3
- #define EOF_STAT 3
-
- /*
- You may tune the following constants:
-
- MAX_INLEVEL the greatest allowed depth for nested #includes.
- IBUF_SIZE size of each input buffer in bytes.
- OBUF_SIZE size of the output buffer in bytes.
- */
- #define MAX_INLEVEL 20
- #define IBUF_SIZE 4096
- #define OBUF_SIZE 4096
-
- /*
- Close all files and exit.
-
- Do not call fatal() or sysabort() from inside
- sysiclose(), sysoclose(), or sys_release().
- */
- void
- sysabort(void)
- {
- SL_DISABLE();
-
- /* Close the output file. */
- if (outn_list != NULL) {
- sysoclose();
- }
-
- /* Close all input files. */
- while(in_list != NULL) {
- sysiclose();
- }
- sysend();
- exit(1);
- }
-
- /*
- Remove one node from the input list.
- */
- static void
- sys_release(void)
- {
- register struct FN * fnp;
-
- TICKB("sys_release");
-
- #ifdef DEBUG
- if (in_list == NULL) {
- t_error("sys_release: can't happen");
- exit(0);
- }
- #endif
-
- /* Remove the node from the input list. */
- fnp = in_list;
- in_list = fnp -> f_next;
- fnp -> f_type = CLOSED;
-
- /* Deallocate the node. */
- if (fnp -> f_buffer != NULL) {
- mg_free(fnp -> f_buffer);
- }
- mg_free( (char *) fnp);
-
- /* Reset the global variables from the next node. */
- if (in_list != NULL) {
- fnp = in_list;
- s_ic = fnp -> f_bufc;
- s_ip = fnp -> f_bufp;
- }
- else {
- s_ic = 0;
- }
-
- TICKX("sys_release");
- }
-
- /*
- Allocate space for a new file node, file buffer and FCB.
- Fill in all other fields to neutral values.
- Return a pointer to the node.
- */
- static struct FN *
- sys_new(int buf_size)
- {
- register struct FN * fnp;
-
- TRACEPB("sys_new", printf("(%d)\n", buf_size));
-
- fnp = (struct FN *) mg_alloc(sizeof(struct FN));
- fnp -> f_buffer = (char *) mg_alloc(buf_size);
- fnp -> f_bufsize = buf_size;
- fnp -> f_next = NULL;
- fnp -> fil_name = NULL;
- fnp -> f_bufp = fnp -> f_buffer;
- fnp -> f_bufc = 0;
- fnp -> f_type = CLOSED;
- fnp -> f_handle = -1;
-
- RETURN_PTR("sys_new", fnp);
- }
-
- /*
- ----- I N P U T L O G I C -----
-
- Set the global variable ch to the next character from the input stream.
- The next call to sysnext() will return another character.
- This is the most often called routine in the whole program.
- */
- #define MAX_MTEXT 2000
-
- static char m_buffer [MAX_MTEXT];
- static char * m_oldp;
- static int m_oldc;
- static int m_flag;
-
- /* this portion of the routine ought to be a macro */
- void
- sysnext(void)
- {
- SL_DISABLE();
-
- if (!s_ic) {
- sysnx1();
- }
- else {
- s_ic--;
- ch = (unsigned char) *s_ip++;
- }
- }
-
- /* This fills ch when the buffer is empty */
- static void
- sysnx1(void)
- {
- register int n;
- register struct FN * fnp;
-
- TICKB("sysnx1");
-
- if (m_flag == TRUE) {
- /* Close the macro buffer. */
- m_flag = FALSE;
-
- /* Restart the previous buffer. */
- s_ic = m_oldc;
- s_ip = m_oldp;
- if (s_ic) {
- s_ic--;
- ch = (unsigned char) *s_ip++;
- RETURN_VOID("sysnx1");
- }
- }
-
- /* A file buffer is empty. */
- fnp = in_list;
- switch(fnp -> f_type) {
-
- case EOF_STAT:
- ch = END_FILE;
- RETURN_VOID("sysnx1");
-
- case INPUT:
- n = raw_read(fnp->f_handle, fnp->f_buffer, IBUF_SIZE);
- if (n > 0) {
- s_ic = n;
- s_ip = fnp -> f_buffer;
- s_ic--;
- ch = (unsigned char) *s_ip++;
- RETURN_VOID("sysnx1");
- }
- else {
- fnp -> f_type = EOF_STAT;
- ch = END_FILE;
- RETURN_VOID("sysnx1");
- }
-
- default:
- TRACEP("sysnx1",
- printf("in_list = %p, in_list -> f_type = %d\n",
- in_list, in_list -> f_type));
- fatal("sysnext: can't happen");
- }
-
- TICKX("sysnx1");
- }
-
- /*
- Push a character so that it will be returned next by sysnext.
-
- The current value of ch is NOT saved.
- */
- void
- syspush(int c)
- {
- SL_DISABLE();
-
- if (m_flag == FALSE) {
-
- TRACEP("syspush", printf("start of macro expansion\n"));
-
- /* Begin to use the macro buffer. */
- m_flag = TRUE;
-
- /* Save the old pointers. */
- m_oldp = s_ip;
- m_oldc = s_ic;
-
- /* Point into the macro buffer. */
- s_ip = &m_buffer[MAX_MTEXT-1];
- *s_ip = (char) c;
- s_ic = 1;
- }
- else if (s_ic >= MAX_MTEXT) {
- fatal("macro expansion too long.");
- }
- else {
- *--s_ip = (char) c;
- s_ic++;
- }
- }
-
- /*
- Push a string so that it will be returned next by sysnext.
- */
- void
- sysspush(register char *s)
- {
- register char *p;
- register int count;
-
- SL_DISABLE();
-
- /* Push in reverse. */
- count = str_len(s);
- p = s;
- p += count;
- p--;
-
- while(count-- > 0) {
- syspush(*p--);
- }
- }
-
- /*
- Close the current input file and pop back one level.
- */
- void
- sysiclose(void)
- {
- register struct FN * fnp;
-
- #ifdef DEBUG
-
- TICKB("sysiclose");
-
- if (t_inlevel < 0) {
- t_error("sysiclose: bad t_inlevel");
- exit(0);
- }
- #endif
-
- /* Close the current input file. */
- fnp = in_list;
- raw_close(fnp -> f_handle);
-
- /* Release the current node. */
- sys_release();
- if (t_inlevel > 0 && in_list == NULL) {
- t_error("sysiclose: null in_list");
- exit(0);
- }
-
- /* Pop back one level. */
- if (in_list != NULL) {
- if (t_inlevel < 0) {
- t_error("sysiclose: unexpected in_list");
- exit(0);
- }
- fnp = in_list;
- s_ic = fnp -> f_bufc;
- s_ip = fnp -> f_bufp;
- t_file = fnp -> fil_name;
- t_line = fnp -> f_line;
- }
- t_inlevel--;
-
- if (t_inlevel == -1) {
- ch = END_FILE;
- }
- else {
- ch = (unsigned char) fnp -> f_lastc;
- }
-
- TRACEPX("sysiclose", printf("returns: t_inlevel=%d\n", t_inlevel));
- }
-
- /*
- Open a file for input.
- Return TRUE if all went well.
- */
- bool
- sysopen(char * name)
- {
- struct FN * fnp;
-
- char * str_galloc();
-
- TRACEPB("sysopen", printf("(%s) t_inlevel: %d\n", name, t_inlevel));
-
- if (m_flag == TRUE) {
- m_flag = FALSE;
- t_error("macro expansion truncated following #include");
- }
-
- /* Save information about the current level on the stack. */
- if (t_inlevel != -1) {
- if (in_list == NULL) {
- fatal("sysopen: can't happen\n");
- }
- fnp = in_list;
- fnp -> f_line = t_line;
- fnp -> f_bufc = s_ic;
- fnp -> f_bufp = s_ip;
- fnp -> f_lastc = (int) ch;
- }
-
- /* Enter a new level. */
- if (t_inlevel >= MAX_INLEVEL) {
- t_error("include files nested too deeply");
- exit(0);
- }
- else {
- t_inlevel++;
- }
-
- /* Create a new file node and link to the front of the list. */
- TRACEP("sysopen", printf("set up new file: call sys_new\n"));
-
- fnp = sys_new(IBUF_SIZE);
- fnp -> f_next = in_list;
- in_list = fnp;
- fnp -> f_type = INPUT;
-
- /* Actually open the file. */
- fnp -> f_handle = raw_open(name);
- if (fnp -> f_handle == -1) {
-
- /* Deallocate the node. */
- TRACEP("sysopen", printf("file open %s fails\n", name));
- sys_release();
- t_inlevel--;
- RETURN_BOOL("sysopen", FALSE);
- }
-
- /* Set the global variables. */
- t_file = str_galloc(name);
- t_line = 1;
- fnp -> fil_name = t_file;
-
- /* Put the first character of the file into ch. */
- s_ic = 0;
- s_ip = fnp -> f_buffer;
- sysnext();
-
- TRACEP("sysopen",
- printf("new t_inlevel=%d, in_list=%p\n", t_inlevel, in_list));
-
- RETURN_BOOL("sysopen", TRUE);
- }
-
- /*
- Close a file opened with raw_open() or raw_creat().
- */
- static void
- raw_close(int handle)
- {
- SL_DISABLE();
-
- #ifdef STANDARD_C
- close (handle);
- #endif
-
- }
-
- /*
- Open the file for writing only.
- Return -1 on error.
- */
- static int
- raw_creat(char *name)
- {
- int h;
-
- #ifdef STANDARD_C
-
- TRACEPB("raw_creat", printf("(%s)\n", name));
-
- chmod(name, S_IREAD | S_IWRITE);
-
- #ifdef TURBOC
- _fmode = O_BINARY;
- #endif /* TURBOC */
-
- RETURN_INT("raw_creat", creat(name, S_IREAD | S_IWRITE));
- #endif
-
- }
-
- /*
- Open the file for reading only.
- Return -1 on error.
- */
- static bool
- raw_open(register char *name)
- {
-
- #ifdef STANDARD_C
- TRACEPB("raw_open", printf("(%s)\n", name));
-
- RETURN_BOOL("raw_open", open(name, O_RDONLY | O_BINARY));
- #endif
-
- }
-
- /*
- Read n bytes from the file fd into buffer[].
-
- Return the number of bytes read.
- */
- static int
- raw_read(int handle, char *buffer, int n)
- {
-
- #ifdef STANDARD_C
- TRACEPB("raw_read", printf("(%d, %s, %d)\n", handle, buffer, n));
-
- RETURN_INT("raw_read", read (handle, buffer, n));
- #endif
-
- }
-
- /*
- Write n bytes from buffer[] to the file fd.
-
- Return the number of bytes written or -1 for error.
- */
- static void
- raw_write(int handle, char *buffer, int n)
- {
- TRACEPB("raw_write", printf("(%d, %s, %d)\n", handle, buffer, n));
-
- #ifdef STANDARD_C
- (void) write (handle, buffer, n);
- #endif
-
- TICKX("raw_write");
- }
-
- /*
- ----- OUTPUT LOGIC -----
- */
-
- /*
- Open a file for output. Only one such file may be open at a time.
-
- Return TRUE if all went well.
- */
- bool
- syscreat(register char * name)
- {
- register struct FN * fnp;
-
- TRACEPB("syscreat", printf("(%s)\n", name));
-
- fnp = outn_list;
-
- #ifdef DEBUG
- if (fnp == NULL || fnp -> f_type != CLOSED) {
- fatal("syscreat: can't happen");
- }
- #endif
-
- /* Actually open the file. */
- fnp -> f_handle = raw_creat(name);
- if (fnp -> f_handle == -1) {
- RETURN_BOOL("syscreat", FALSE);
- }
- fnp -> f_type = OUTPUT;
-
- /* The output buffer is empty. */
- s_oc = 0;
- s_op = fnp -> f_buffer;
-
- RETURN_BOOL("syscreat", TRUE);
- }
-
- /*
- Close the output file(s).
- */
- void
- sysoclose(void)
- {
- register struct FN * fnp;
-
- TICKB("sysoclose");
-
- fnp = outn_list;
- if (fnp != NULL && fnp -> f_type != CLOSED) {
- syscput(END_FILE);
- sys_close(fnp, s_oc);
- }
-
- TICKX("sysoclose");
- }
-
- static void
- sys_close(register struct FN * fnp, int count)
- {
- TRACEPB("sys_close", printf("(%p, %d)\n", fnp, count));
-
- /* Finish writing the last sector(s). */
- if (count) {
- raw_write(fnp->f_handle, fnp->f_buffer, count);
- }
-
- /* Close the file. */
- raw_close(fnp -> f_handle);
- fnp -> f_type = CLOSED;
-
- TICKX("sys_close");
- }
-
- /*
- Put a newline to the output file.
- */
- void
- sysnlput(void)
- {
- struct FN * fnp;
-
- SL_DISABLE();
-
- *s_op++ = '\r';
- s_oc++;
- if (s_oc == OBUF_SIZE) {
- fnp = outn_list;
- raw_write(fnp->f_handle, fnp->f_buffer, OBUF_SIZE);
- s_op = fnp -> f_buffer;
- *s_op++ = '\n';
- s_oc = 1;
- }
- else {
- *s_op++ = '\n';
- s_oc++;
- if (s_oc == OBUF_SIZE) {
- fnp = outn_list;
- raw_write(fnp->f_handle, fnp->f_buffer, OBUF_SIZE);
- s_oc = 0;
- s_op = fnp -> f_buffer;
- }
- }
-
- /* Give user a chance to stop. */
- (void) syscsts();
- }
-
- /*
- Put a non-newline to the output file.
- This is the most called routine after sysnext().
- */
- void
- syscput(char c)
- {
- struct FN * fnp;
-
- SL_DISABLE();
-
- #ifdef DEBUG
- if (c == '\n') {
- printf("syscput: shouldn't happen\n");
- sysnlput();
- return;
- }
- #endif
-
- *s_op++ = c;
- s_oc++;
- if (s_oc == OBUF_SIZE) {
- fnp = outn_list;
- raw_write(fnp->f_handle, fnp->f_buffer, OBUF_SIZE);
- s_oc = 0;
- s_op = fnp -> f_buffer;
- }
- }
-
- /*
- Put one string to the output file.
- */
- void
- syssput(register char * s)
- {
- SL_DISABLE();
-
- while (*s) {
- syscput(*s++);
- }
- }
-
- /*
- Shut down the system. This routine is called just before doing an
- exit(0). Do any last minute things here.
- */
- void
- sysend(void)
- {
- TICK("sysend");
- }
-
- /*
- Initialize the system module. This routine is called just once before
- any other calls to this module. Do any initilizing here.
- */
- void
- sysinit(void)
- {
- register struct FN * fnp;
-
- TICKB("sysinit");
-
- /* Portable part. */
- t_inlevel = -1;
- t_line = 0;
- t_file = NULL;
-
- in_list = NULL;
- m_flag = FALSE;
-
- /* Allocate node for output file. */
- outn_list = sys_new(OBUF_SIZE);
-
- TRACEPX("sysinit", printf("outn_list = %p\n", outn_list));
- }
-
- /*
- Return 0 if no character is ready from the keyboard.
- Otherwise, return the character itself.
- */
- int
- syscsts(void)
- {
- SL_DISABLE();
-
- #ifdef STANDARD_C
- if (kbhit()) {
- return fgetchar() & 0x7f;
- }
- else {
- return 0;
- }
- #endif
-
- }
-